/**
 * 
 */
package org.yelongframework.support.properties.wired;

import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.Set;
import java.util.stream.Collectors;

import org.yelongframework.ognl.OgnlWrapper;

/**
 * 属性装配处理器
 * 
 * @param <T> bean type
 * @since 1.0.0
 */
public final class PropertiesWiredProcessor<T> {

	private final T obj;

	private final Properties properties;

	private final String propertyPrefix;

	private final OgnlWrapper ognlWrapper;

	/**
	 * @param obj              被注入属性的对象
	 * @param properties       属性对象
	 * @param propertiesPrefix 前缀 可以为空
	 */
	public PropertiesWiredProcessor(T obj, Properties properties, String propertyPrefix) {
		this.propertyPrefix = propertyPrefix;
		this.properties = properties;
		this.obj = obj;
		ognlWrapper = new OgnlWrapper();
		ognlWrapper.put("properties", this.obj);
		ognlWrapper.setRoot(this.obj);
	}

	/**
	 * 将属性装配到对象中
	 * 
	 * @return 装配好属性的对象
	 */
	public T wiredObj() {
		// 配置文件中所有的属性名称
		Set<String> propertiesNames = properties.stringPropertyNames();
		List<OnglExpressionAndPropertyName> onglExpressionAndPropertyNameList = null;
		if (null != propertyPrefix) {
			// 置换为ognl表达式与属性名称的映射
			onglExpressionAndPropertyNameList = propertiesNames.stream()
					// 去除非此属性类的前缀的属性名称
					.filter(x -> x.startsWith(propertyPrefix))
					.map(x -> new OnglExpressionAndPropertyName(x.substring(propertyPrefix.length() + 1), x))
					.collect(Collectors.toList());
		} else {
			onglExpressionAndPropertyNameList = new ArrayList<>();
			for (String propertiesName : propertiesNames) {
				onglExpressionAndPropertyNameList
						.add(new OnglExpressionAndPropertyName(propertiesName, propertiesName));
			}
		}
		for (OnglExpressionAndPropertyName entry : onglExpressionAndPropertyNameList) {
			String value = properties.getProperty(entry.getPropertyName());
			if (null == value) {
				continue;
			}
			ognlWrapper.setValue(entry.getOgnlExpression(), value);
		}
		return obj;
	}

	public T getObj() {
		return obj;
	}

	public String getPropertyPrefix() {
		return propertyPrefix;
	}

	public Properties getProperties() {
		return properties;
	}

	public Class<?> getObjClas() {
		return obj.getClass();
	}

	/**
	 * ognl表达式与属性名称映射
	 */
	private static class OnglExpressionAndPropertyName {

		private final String ognlExpression;

		private final String propertyName;

		public OnglExpressionAndPropertyName(String ognlExpression, String propertyName) {
			this.ognlExpression = ognlExpression;
			this.propertyName = propertyName;
		}

		public String getOgnlExpression() {
			return ognlExpression;
		}

		public String getPropertyName() {
			return propertyName;
		}

	}

}
